import { TableDatas } from './table-datas';
import { Config } from './config';
import { Inject } from '../decorators/inject';
import { NExcel } from '../types';
import { Injectable } from '../decorators/inject';
import { TableEvent } from './table-event';
import { Hook } from './hook';
import { MergeCell } from './merge-cell';
import { CellRender } from './cell-render';
import { EditLayer } from './edit-layer';
import { FillRender } from './fill-render';
import { Cache } from './cache';
import { FreezeRender } from './freeze-render';
import { BorderRender } from './border-render';
import { MergeCellRender } from './mergecell-render';
import { FullControl } from './full-control';
@Injectable('DataRender')
export class DataRender {
    protected renderedCell: { row: number, col: number }[] = [];
    protected ctx: CanvasRenderingContext2D;
    protected fillCtx: CanvasRenderingContext2D;
    protected freezeInfo = {
        width: 0,
        height: 0,
        startX: 0,
        startY: 0
    }
    constructor(
        protected datas: TableDatas,
        protected conf: Config,
        @Inject(NExcel.TableDataCanvasToken) protected canvasDataEle: HTMLCanvasElement,
        @Inject(NExcel.TableDataCanvasFillToken) protected canvasDataFillEle: HTMLCanvasElement,
        protected tableEvent: TableEvent,
        protected hook: Hook,
        protected mergeCell: MergeCell,
        protected cellRender:CellRender,
        protected editLayer: EditLayer,
        protected fillRender: FillRender,
        protected cache: Cache,
        protected freezeRender: FreezeRender,
        protected borderRender: BorderRender,
        protected mergeCellRender: MergeCellRender,
        protected fullControl: FullControl
    ) {
    }
    public init() {
        this.ctx = this.canvasDataEle.getContext('2d');
        this.fillCtx = this.canvasDataFillEle.getContext('2d');
    }
    protected berforeRender() {
        const width = this.canvasDataEle.clientWidth * this.conf.pixelRatio;
        const height = this.canvasDataEle.clientHeight * this.conf.pixelRatio;
        let startY = this.conf.header.col.height // + this.freezeRender.getStartRowHeight();
        this.ctx.clearRect(0, 0, width + 1, height + 1);
        this.fillCtx.clearRect(0, 0, width + 1, height + 1);
        this.renderedCell = [];
        let w = this.freezeRender.getStartColWidth();
        let h = this.freezeRender.getStartRowHeight();
        this.freezeInfo = {
            width: w,
            height: h,
            startX: this.conf.header.row.width + w,
            startY: this.conf.header.col.height + h
        }

    }
    protected renderSingleCell(row: number, col: number) {
        if(!this.datas.rowIsExist(row)) {
            return;
        }
        let rowInstance = this.datas.getRow(row);
        if(!rowInstance.colIsExist(col)) {
            return;
        }
        let cell = rowInstance.getCell(col);
        let info = this.cache.getRangeRectInfo({row,col});
        if(cell.fill) {
            let x = info.start.x + this.conf.pixelRatio;
            let y = info.start.y;
            let w = info.w + 1;
            let h = info.h + 1;
            this.fillRender.addFill({x, y}, {w: w - 2 * this.conf.enlarge, h: h - 2 * this.conf.enlarge}, cell.fill.background.color);
        }
        if(cell.border != null) {
            this.borderRender.drawBorder({row, col, rowspan: 1, colspan: 1},{x: info.start.x, y: info.start.y}, {w: info.w + 1, h: info.h + 1},cell.border);
        }
        return cell;
    }
    protected renderQuadrantMergeCell(clip: TRect, row: number, col: number, opt?: {padding: {top: number, right: number, bottom: number, left: number}}) {
        if(!this.datas.rowIsExist(row)) {
            return;
        }
        let rowInstance = this.datas.getRow(row);
        if(!rowInstance.colIsExist(col)) {
            return;
        }
        let cell = rowInstance.getCell(col);
        if(cell.fill) {
            let x = clip.x;
            let y = clip.y;
            let w = clip.w;
            let h = clip.h;
            this.fillRender.addFill({x, y}, {w, h: h}, cell.fill.background.color);
        }
    }
    protected renderQuadrant1() {
        const {row: freezeRow, col: freezeCol} = this.conf.freeze;
        for(let row = 0; row <= freezeRow;row++) {
            for(let col = 0; col <= freezeCol;col++) {
                let merge = this.mergeCell.getMerge(row, col);
                if(merge) {
                    continue;
                }
                this.cellRender.renderSingleCell(row, col, 1);
            }
        }
    }
    protected renderQuadrant2() {
        const {row: freezeRow } = this.conf.freeze;
        for(let row = 0; row <= freezeRow;row++) {
            for(let col = this.conf.visibleBoundary.col; col <= this.conf.visibleBoundary.endCol;col++) {
                let merge = this.mergeCell.getMerge(row, col);
                if(merge) {
                    continue;
                }
                this.cellRender.renderSingleCell(row, col, 2);
            }
        }
    }
    protected renderQuadrant3() {
        const {col: freezeCol} = this.conf.freeze;
        for(let row = this.conf.visibleBoundary.row; row <= this.conf.visibleBoundary.endRow; row++) {
            for(let col = 0; col <= freezeCol;col++) {
                let merge = this.mergeCell.getMerge(row, col);
                if(merge) {
                    continue;
                }
                this.cellRender.renderSingleCell(row, col, 3);
            }
        }
    }
    protected renderQuadrant4() {
        for(let row = this.conf.visibleBoundary.row; row <= this.conf.visibleBoundary.endRow; row++) {
            for(let col = this.conf.visibleBoundary.col; col <= this.conf.visibleBoundary.endCol;col++) {
                let merge = this.mergeCell.getMerge(row, col);
                if(merge) {
                    continue;
                }
                this.cellRender.renderSingleCell(row, col, 4);
            }
        }
    }
    public render() {
        this.hook.beforeDataRender.excute();
        this.berforeRender();
        this.cellRender.beforeRender();
        /**
         1|2
         3|4
         */
        this.renderQuadrant1();
        this.renderQuadrant2();
        this.renderQuadrant3();
        this.renderQuadrant4();
        this.mergeCellRender.render();
        this.fillRender.render();
    }
    // protected isCompeletInVisible(merge: TMergeCell) {
    //     const {row: startRow, col: startCol, endRow, endCol} = this.conf.visibleBoundary;
    //     if(merge.row >= startRow && merge.row <= endRow 
    //         && merge.row + merge.rowspan - 1 >= startRow && merge.row + merge.rowspan - 1 <= endRow
    //         && merge.col >= startCol && merge.col <= endCol
    //         && merge.col + merge.colspan - 1 >= startCol && merge.col + merge.colspan - 1 <= endCol) {
    //             return true;
    //         }
    //     return false;
    // }
    // protected isVisibleMerCell(merge: TMergeCell): boolean {
    //     const {row: freezeRow, col: freezeCol} = this.conf.freeze;
    //     if(merge.row < freezeRow || merge.col < freezeCol) {
    //         // return true
    //     }
    //     const {row: startRow, col: startCol, endRow, endCol} = this.conf.visibleBoundary;
    //     for(let row = merge.row; row < merge.row + merge.rowspan; row++) {
    //         for(let col = merge.col; col < merge.col + merge.colspan; col++) {
    //             if(row >= startRow && row <= endRow && col >= startCol && col <= endCol) {
    //                 return true;
    //             }
    //         }
    //     }
    //     return false;
    // }
    protected drawFill(start: TCoord, size: TSize, color: string) {
        this.fillCtx.save();
        this.fillCtx.beginPath();
        this.fillCtx.fillStyle = color;
        let x = start.x - 1;
        let y = start.y - 1;
        let w = size.w;
        let h = size.h;
        if (x < this.conf.header.row.width) {
            w = w - (this.conf.header.row.width - x);
            x = this.conf.header.row.width;
        }
        if (y < this.conf.header.col.height) {
            h = h - (this.conf.header.col.height - y);
            y = this.conf.header.col.height;
        }
        this.fillCtx.fillRect(x, y, w, h);
        this.fillCtx.restore();
    }
}